package graph;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Set;

public class Graph {
	
	Hashtable<Vertex,ArrayList<Edge>> h;
	
	public Graph(){
		h = new Hashtable<Vertex,ArrayList<Edge>>(100);
	}
	
	public void add(Edge e){
		//add an edge between two vertices
		//if either of the vertices does not exist, add that vertex to the hashtable
		//if the edgelist does not contain that edge, add the edge
		
			Vertex v1 = e.getV1();
			Vertex v2 = e.getV2();
			
			addVertex(v1);
			addVertex(v2);
			
			ArrayList<Edge> edges = h.get(v1);
			if(!edges.contains(e)){
			edges.add(e);
			}
		}
	
	public void remove(Edge e){
		//removes one instance of edge e
		Vertex v = e.getV1();
		
		if(h.containsKey(v)){
			ArrayList<Edge> edges = h.get(v);
			
			if(edges != null){
			edges.remove(e);
			}
		}
	}
	
	public void addVertex(Vertex v){
		if(!h.containsKey(v)){
			h.put(v, new ArrayList<Edge>());
		}
	}
	
	public void removeVertex(Vertex v){ //Removing a vertex is expensive because we need to iterate through all edges
		if(h.containsKey(v)){
			h.remove(v);
		}
		Collection<ArrayList<Edge>> allEdges = h.values();
		for(ArrayList<Edge> eSet : allEdges){
			for(Edge e : eSet){
				if(e.getV2()==v){
					eSet.remove(e);
				}
			}
		}
	}
	
	public ArrayList<Vertex> getAdjacent(Vertex v){
		
		ArrayList<Vertex> A = new ArrayList<Vertex>();
		
		if(h.containsKey(v)){
			ArrayList<Edge> edges = h.get(v);
			for(Edge e: edges){
				Vertex vprime = e.getV2();
				if(!(A.contains(vprime))){
					A.add(vprime);
				}
			}
			return A;
		}
		else {
			//Vertex does not exist in the graph, so return null
			return null;
		}
	}
	
	public Set<Vertex> getVertexSet(){
		return h.keySet();
	}
	
	public Edge getAdjoiningEdge(Vertex v1, Vertex v2){
		ArrayList<Edge> edges = h.get(v1);
		for(Edge e:edges){
			if(e.getV2().equals(v2)){
				return e;
			}
		}
		return null;
	}
	
	public Collection<ArrayList<Edge>> getAdjacencyList(){
		return h.values();
	}
	
	public void print(){
		System.out.println("Vertices: ");
		Set<Vertex> s = this.getVertexSet();
		for(Vertex v : s){
			System.out.println(v);
		}
		
		System.out.println("----");
		Collection<ArrayList<Edge>> adjacencyList = this.getAdjacencyList();
		for(ArrayList<Edge> eList : adjacencyList){
			for(Edge e : eList){
				System.out.println(e);
			}
		}
		System.out.println("----");
	}
	
	public void toPajekNet(String fileName){
		ArrayList<Vertex> V = new ArrayList<Vertex>(this.getVertexSet());
		toPajekNet(fileName,V);
	}
	
	public void toPajekNet(String fileName,ArrayList<Vertex> V){
		//Outputs NET
		File f = new File(fileName+".net");
		
		PrintWriter p = null;
		try {
			p = new PrintWriter(new FileWriter(f));
		}
		catch(IOException e){
			System.out.println("Invalid file name for Pajek output.");
			return;
		}
		
		p.println("*Vertices "+V.size());
		
		int i=1;
		for(Vertex v : V){
			p.println(i+" "+v.label+" "+v.getX()/Math.pow(h.size()+1, 0.5)+" "+v.getY()/(Math.pow(h.size()+1, 0.5)));
			i = i+1;
		}
		
		Collection<ArrayList<Edge>> adjacencyList = this.getAdjacencyList();
		
		p.println("*Edges");
		
		for(ArrayList<Edge> E : adjacencyList){
			for(Edge e : E){
				Vertex v1 = e.getV1(); Vertex v2 = e.getV2();
				p.print((V.indexOf(v1)+1)+" "+(V.indexOf(v2)+1));
				double[] d = e.getWeight();
				//for(int j=0;j<d.length;j++){
				//	p.print(" "+d[j]);
				//}
				p.print(" "+(d[0]+1));
				p.print(" l "+'\"'+d[1]+'\"');
				p.println();
			}
		}
		
		p.flush();
		p.close();
		
	}
	
	public static void main(String args[]){
		Graph g = new Graph();
		for(int i=0;i<6;i=i+2){
			g.add(new Edge(new Vertex(""+i,0,i),new Vertex(""+(i+1),0,(i+1))));
		}
		g.print();
		
		Vertex v = new Vertex("2",0,2);
		g.removeVertex(v);
		g.print();
	}
	
}
